import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;


/**
 * класс будет возвращать массивы с данными, объекты, их типы, атрибуты, параметра
 * и их соответствия.
 * ввел методы
 *        String[]  getObject_types();  -  возвращает массив содержащий имен типоп объектов
 *        int  getObject_type_index(String type);  - возвращает порядковый номер типа
 *        String[]  getObjects_Name_Whith_type(String type);  - возвращает масив объекто типа object_type 
 *        String[]  getObjects_Name_Whith_type(int index); -  возвращает масив объекто типа c 
 *                                                            порядковым номером index
 *        int  getObject_name_type_index(String object_name);  -  возвращает порядковый типа объекта 
 *                                                           с именем object_name
 *        int  getObject_name_index(String type, String name) - возвращает порядковый номер объекта 
 *                                                              типа type с именем object name
 *        String[]  getParams_Object_name(String object, String type);  - возвращает массив параметров объекта 
 *                                                                  с именем object типа type
 *        String[]  getParams_Object_index(int object_index);  - возвращает массив параметров объекта
 *                                                                          c номером имени object_index
 *                                                                          и нмером типа type_index
 *        String[]  getAttributes_of_type(String type);  -  вовращает массив атрииботов типа type
 *        int  getAttributes_index(String name, String type);    - возвращает номер атрибута с именем name у типа type
 *        String  getAttributes_name(int attr_index, int type_index);  - возвращает номер атрибута с
 *                                                                       номером имени attr_index, 
 *                                                                       и номером типа type_index
 *
 */
@SuppressWarnings("ALL")
public class import_from_XML  {
    public String[] attr_names;
    public String[] object_names;
    public String[] object_type;
    public String[] params_value;
    public Number[] object_index;
    public Number[] param_index;
    public Number[] param_attr_index;
    public Number[] attr_object_type_index;

    public   String[]  getObject_types(){
        
        return object_type;
        
    }
    
    public Number  getObject_type_index(String type){
        int index = -1;
        for(int i = 0; i < object_type.length; i++ ){
        
            if (object_type[i].equalsIgnoreCase(type)){
                 index = i;
            }
            else continue;
            
        }
         return index;
        
    }
    
    public String[]  getObjects_Name_Whith_type(String type){
         ArrayList<String>  Objects_Nam = new ArrayList<String>();
         for (int i = 0; i < object_names.length; i++){
             if (getObject_type_index(type).equals(object_index[i]) ){
                 Objects_Nam.add(object_names[i]);
                 
             }
             else continue;
         }
        return Objects_Nam.toArray(new String[Objects_Nam.size()]);
     }

    public Number  getObject_name_Type_index(String object_name){
        Number index = -1;
        for (int i = 0; i < object_names.length; i++){
            if (object_names[i].equalsIgnoreCase(object_name)) {
             index = object_index[i];   
                
            }
            else continue;
            
        }
        
        return index;
    }

    public Number  getObject_name_index(String type, String name){
        int index = -1;
        
        for (int i = 0; i < object_names.length; i++){
            
            if ((getObject_name_Type_index(name).equals(getObject_type_index(type)))
                    && object_names[i].equalsIgnoreCase(name)){
                index = i;
            }
          continue;  
        }
         
        return index;
    }
    
    public String[]  getParams_Object_name(String object){
        ArrayList<String>  object_params = new ArrayList<String>();
        
        for (int i = 0; i < object_names.length; i++){
            if(object_names[i].equalsIgnoreCase(object)){

                for (int j = 0; j < param_index.length; j++)
                    if (param_index[j].equals(i)){
                        object_params.add(params_value[j]);  
                    }
                    else continue;
            }
            else continue;
           
            
        }
        return object_params.toArray(new String[object_params.size()]);
    }
    
    public String[]  getParams_Object_index(Number object_index){
        ArrayList<String>  object_params = new ArrayList<String>();
        
        for (int i = 0; i < params_value.length; i++){
            if (object_index.equals(param_index[i])){
                object_params.add(params_value[i]);
            }
            else continue;
        }
        
        return object_params.toArray(new String[object_params.size()]);
        
    }
    
    public String[]  getAttributes_of_type(String type){
        ArrayList<String> attr_name = new ArrayList<String>();
        Number i = getObject_type_index(type);
        for (int j = 0; j < attr_object_type_index.length; j++ ){
            if (attr_object_type_index[j].equals(i)){
                attr_name.add(attr_names[j]);                
            }
            else continue;
        }
                                  
        return attr_name.toArray(new String[attr_name.size()]);
    }
    
    public Number  getAttributes_index(String name, String type){
        Number index = -1;

        
        for (int j = 0; j < attr_names.length; j++){
            
                if (attr_names[j].equalsIgnoreCase(name) && 
                        attr_object_type_index[j].equals(getObject_type_index(type))){
                    index = j;
                }
                else continue;
            
        }
        
        
        return index;
    }

    public String  getAttributes_name(int attr_index){
               
        
        return attr_names[attr_index];
    }
    

    public void import_column_name(File f) throws SAXException, ParserConfigurationException {

        
        
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        SAXHandler row_Hend = new SAXHandler();
        try {
            parser.parse(f, row_Hend);
        } catch (IOException e) {
            e.printStackTrace();
        }


        object_type = row_Hend.getObject_type();


        /**
         *  вспомогательный элемент для формирования object_names and attr_names
         *      String[] attr_names;    
         *      String[] object_names;       
         *      String[] params_value;
         */
        
        ArrayList<String> help_attr = new ArrayList<String>();
        ArrayList<String> help_obj = new ArrayList<String>();
        ArrayList<String> help_param = new ArrayList<String>();
        ArrayList<String> help = new ArrayList<String>();
        ArrayList<Number> help_attr_object_type = new ArrayList<Number>();
        ArrayList<Number> help_object_type = new ArrayList<Number>();
        ArrayList<Number> help_param_index = new ArrayList<Number>();
        ArrayList<Number> help_param_attr_index = new ArrayList<Number>();
        Collections.addAll(help, row_Hend.getCell());
        Number[] row_index =    row_Hend.getRow_index();    //соответствие строки и данных
        Number[] list_index =  row_Hend.getList_Index();   //соответствие типа  и объекта
        Number[] column_idex = row_Hend.getCell_Inex();    //соответствие столбца и данных
        

        Iterator<String> it_help = help.iterator();
        int j = -1;
        
        while(it_help.hasNext()){
            j++;
            String help_str= it_help.next();
            if(row_index[j].equals(0)&&(!help_str.equalsIgnoreCase("Name"))){

                 help_attr.add(help_str);
                 help_attr_object_type.add(list_index[j+1]);
            }


        }
        attr_names = help_attr.toArray(new String[help_attr.size()]);
        attr_object_type_index = help_attr_object_type.toArray(
                new Number[help_attr_object_type.size()]);

        it_help = help.iterator();


            j = -1;

            while (it_help.hasNext()) {
                j++;
                String str = it_help.next();
                if (column_idex[j].equals(0)&&!str.equalsIgnoreCase("Name")) {
                    help_obj.add(str);
                    help_object_type.add(list_index[j]);
            } else continue;
            }


        object_names = help_obj.toArray(new String[help_obj.size()]);
        object_index = help_object_type.toArray(new Number[help_object_type.size()]);

        /**
         * Заполнение    params_value, param_index, param_attr_index
         * param_index содержит соответствие параметра и объекта
         * param_attr_index сщдержит соответствие атрибута и параметра
         * 
         */

        int obj_id = -1;
        String help_str,
               help_object; 
        Iterator<String> it_object = help_obj.iterator();
      try{
        while (it_object.hasNext()){
            help_object = it_object.next();
            obj_id++;
            j = -1;
            it_help = help.iterator();
            while (it_help.hasNext()){
                help_str = it_help.next();
                j++;
                if (help_object.equalsIgnoreCase(help_str)){
                    Number t = row_index[j];
                    if (it_help.hasNext()){
                        help_str = it_help.next();
                    }
                    j++;
                    while (row_index[j].equals(t)){

                        help_param.add(help_str);
                        help_param_index.add(obj_id);
                        try{
                        help_param_attr_index.add(column_idex[j]);
                        } catch (ArrayIndexOutOfBoundsException ex){
                            ex.printStackTrace();
                        }
                        if (it_help.hasNext()){
                            help_str = it_help.next();
                           
                        }
                        j++;
                        if (j >= (row_index.length )){
                                  j = 0;
                        }

                    }

                }
            }
            
        }
      }catch (ArrayIndexOutOfBoundsException ex){
          ex.printStackTrace();
      }
        params_value = help_param.toArray(
                new String[help_param.size()]);

        param_index = help_param_index.toArray(
                new Number[help_param_index.size()]);

        param_attr_index = help_param_attr_index.toArray(
                new Number[help_param_attr_index.size()]);
    }
}


/**
 * @see -
 *   класс наследник DefaultHandler основные методы
 *   metod getRow_index()  возвращает массив соответствия строки и ячейки
 *   metod getCell()       возвращает массив данных в ячейках
 *   metod getList_Index(      возвращает массив соответствия листа и строки
 *   metod getObject_type()      возвращает массив имен типов объектов
 *
 *   @version 1.0
 */
 class SAXHandler extends DefaultHandler
{
    private ArrayList<String> list;    //содекжит имена листов
    private ArrayList<Number> ListName_index;  //соответствие ячейки и листа
    private ArrayList<Number> row_Index;       //сщдержит соответствие ячейки и строки
    private ArrayList<Number> column_index;    //содержит соответствие колонок и данных
    private ArrayList<String> cell;            //содержит данные в ячейках
    private boolean isTag = false,
                    isCell = false,    
                    isList = false;
    
    private int i = -1,   //индекс листа
                j = -1,   //индекс столбца на листе
                c = -1,   //индекс перекрестка ячейки
                column = 0;  //индекс столбца



    public Number[] getRow_index(){

        return row_Index.toArray(new Number[row_Index.size()]);
    }


    public String[] getCell(){
        
        return cell.toArray(new String[cell.size()]);
    }

    public Number[] getCell_Inex(){

        return column_index.toArray(new Number[column_index.size()]);
    }
    
    public Number[] getList_Index(){
        
        return ListName_index.toArray(new Number[ListName_index.size()]);
    }
    
    public String[] getObject_type()
    {
        return list.toArray(new String[list.size()]);
    }
    @Override
    public void startDocument() throws SAXException
    {
        list = new ArrayList<String>();
        cell = new ArrayList<String>();
        ListName_index = new ArrayList<Number>();
        row_Index = new ArrayList<Number>();
        column_index = new ArrayList<Number>();
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    {

        if (qName.equals("Worksheet")) {
            list.add(attributes.getValue(0));
            i++;
            isList = true;
        }
        else {
             if ( "Cell".equals(qName)) {
                 isCell = "Cell".equals(qName);
                 c ++;
                 column_index.add(column);
             }
            isTag = "Data".equals(qName);
            if (qName.equals("Row")) {
               j++;
        }
        }
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException
    {      
           if(isTag&&isCell&&(c == 0)&&isList){
               //услови разравы данных в ch[]
               if (start != 0){
               cell.add(new String(ch, start, length));
               ListName_index.add(i);
               row_Index.add(j);
                   c++;
               }
        else {
              String buff =  cell.get(cell.size()-1);
               buff = buff  +  new String(ch,start,length);
              cell.remove(cell.size() - 1);
              cell.add(buff);
           }
           }
        else     //сдесь контроль записи в поле Data у xml документа
        if(isTag&isCell&&(c > 0)) {
               String buff =  cell.get(cell.size()-1);
               buff = buff  +  new String(ch,start,length);
               cell.remove(cell.size() - 1);
               cell.add(buff);
               c++;
           }
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException
    {
        if(qName.equals("Worksheet")){
            isList = false;
            j = -1;
        }
        if (qName.equals("Cell")){
            c = -1;
            isCell = false;
            column++;
        }
        if (qName.equals("Data")){
            isTag = false;
        }
         if (qName.equals("Row")){
             column = 0;
         }
    }
    @Override
    public void endDocument() throws SAXException
    {
    }
}